<?php

/*
 * Copyright 2008 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#namespace tehframework\annotations;

#use \OutOfRangeException;

class DocBlock
{
	/**
	 * @var string
	 */
	protected $shortDescription;
	
	/**
	 * @var string
	 */
	protected $longDescription;
	
	/**
	 * @var array<string,Tag[]>
	 */
	protected $tags = array();
	
	/**
	 * @var array<string,Annotation[]>
	 */
	protected $annotations = array();

	/**
	 * @param string? $shortDescription
	 * @param string? $longDescription
	 * @param array<string,Tag[]> $tags
	 * @param array<string,Annotation[]> $annotations
	 * @param array<string,array<string,Annotation[]>> $parameterAnnotations
	 */
	public function __construct(
		$shortDescription = null,
		$longDescription = null,
		array $tags = array(),
		array $annotations = array())
	{
		$this->shortDescription = empty($shortDescription)
			? null : $shortDescription;
		$this->longDescription  = empty($longDescription)
			? null : $longDescription;
		$this->tags             = $tags;
		$this->annotations      = $annotations;
	}
	
	/**
	 * @return string
	 */
	public function __toString()
	{
		$str = '';
		
		if ($this->hasShortDescription())
		{
			$str .= $this->getShortDescription() . PHP_EOL . PHP_EOL;
		}
		
		if ($this->hasLongDescription())
		{
			$str .= $this->getLongDescription() . PHP_EOL . PHP_EOL;
		}
		
		if ($this->hasAnyTags())
		{
			foreach ($this->getAllTags() as $tagName => $tag)
			{
				$str .= '@' . $tagName . '<' . get_class($tag) . '>' . PHP_EOL;
			}
		}
		
		if ($this->hasAnyAnnotations())
		{
			foreach ($this->getAllAnnotations() as $annName => $ann)
			{
				$str .= '@' . $annName . '<' . get_class($ann) . '>' . PHP_EOL;
			}
		}
		
		return $str;
	}
	
	/**
	 * @return boolean
	 */
	public function hasShortDescription()
	{
		return !empty($this->shortDescription);
	}
	
	/**
	 * @return string?
	 */
	public function getShortDescription()
	{
		return $this->shortDescription;
	}
	
	/**
	 * @return boolean
	 */
	public function hasLongDescription()
	{
		return !empty($this->longDescription);
	}
	
	/**
	 * @return string?
	 */
	public function getLongDescription()
	{
		return $this->longDescription;
	}
	
	/**
	 * @return boolean
	 */
	public function hasAnyTags()
	{
		return count($this->tags) !== 0;
	}
	
	/**
	 * @param  string $tagName
	 * @return boolean
	 */
	public function isTaggedWith($tagName)
	{
		return isset($this->tags[$tagName]);
	}
	
	/**
	 * @param  string $tagName
	 * @return Tag
	 * @throws OutOfRangeException
	 */
	public function getTag($tagName)
	{
		if (!isset($this->tags[$tagName]))
		{
			throw new OutOfRangeException(sprintf(
				'[%s] tag does not exist.', $tagName
			));
		}
		
		return $this->tags[$tagName][0];
	}
	
	/**
	 * @param  string $tagName
	 * @return Tag[]
	 * @throws OutOfRangeException
	 */
	public function getTagArray($tagName)
	{
		if (!isset($this->tags[$tagName]))
		{
			throw new OutOfRangeException(sprintf(
				'[%s] tag does not exist.', $tagName
			));
		}
		
		return $this->tags[$tagName];
	}
	
	/**
	 * @return array<string,Tag[]>
	 */
	public function getAllTags()
	{
		return $this->tags;
	}
	
	/**
	 * @return boolean
	 */
	public function hasAnyAnnotations()
	{
		return count($this->annotations) !== 0;
	}
	
	/**
	 * @param  string $annotationName
	 * @return boolean
	 */
	public function isAnnotatedWith($annotationName)
	{
		return isset($this->annotations[$annotationName]);
	}
	
	/**
	 * @param  string $annotationName
	 * @return Annotation
	 * @throws OutOfRangeException
	 */
	public function getAnnotation($annotationName)
	{
		if (!isset($this->annotations[$annotationName]))
		{
			throw new OutOfRangeException(sprintf(
				'[%s] annotation does not exist.', $annotationName
			));
		}
		
		return $this->annotations[$annotationName][0];
	}
	
	/**
	 * @param  string $annotationName
	 * @return Annotation[]
	 * @throws OutOfRangeException
	 */
	public function getAnnotationArray($annotationName)
	{
		if (!isset($this->annotations[$annotationName]))
		{
			throw new OutOfRangeException(sprintf(
				'[%s] annotation does not exist.', $annotationName
			));
		}
		
		return $this->annotations[$annotationName];
	}
	
	/**
	 * @return array<string,Annotation[]>
	 */
	public function getAllAnnotations()
	{
		return $this->annotations;
	}
}